﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using StockFinder.Entities;
using System.Text.RegularExpressions;

namespace StockFinder.HistoricPricesExtractor
{
    public class HistoricPricesExtractorEngine
    {
        /*
         * 0. symbol
         * 1. date to MONTH - 1 
         * 2. date to DAY
         * 3. date to YEAR
         * 4. date from MONTH - 1
         * 5. date from DAY
         * 6. date from YEAR
         * */
        const string BASE_URL = "http://ichart.finance.yahoo.com/table.csv?s={0}&amp;d={1}&amp;e={2}&amp;f={3}&amp;g=d&amp;a={4}&amp;b={5}&amp;c={6}&amp;ignore=.csv";

        const string DOWNLOAD_SPREADSHEET_PATTERN = "<a href=\"([\\w\\./:\\?&;=]+)\">Download To Spreadsheet</a>";

        const string PAGE_NOT_EXIST = "Sorry, the page you requested was not found";

        public HistoricPricesExtract GetHistoricPrices(DateTime fromDate, DateTime toDate, Symbol symbol)
        {
            HistoricPricesExtract extraction = new HistoricPricesExtract();

            //create the url
            string pricesUrl = string.Format(
                BASE_URL,
                symbol.Name,
                toDate.Month - 1,
                toDate.Day,
                toDate.Year,
                fromDate.Month - 1,
                fromDate.Day,
                fromDate.Year);

            //now get the spreadsheet
            HttpWebRequest webRequest = HttpWebRequest.Create(pricesUrl) as HttpWebRequest;

            HttpWebResponse webResponse = null;

            try
            {
                webResponse = (HttpWebResponse)webRequest.GetResponse();

                //got a response
                extraction.HistoricPricesExtractResult = "SUCCESS";
            }
            catch (WebException webException)
            {
                //timeout?
                //if (webException.Status == WebExceptionStatus.Timeout)
                //{
                //    //probably internet down so quit
                //    extraction.HistoricPricesExtractResult = HistoricPricesExtractResult.TIMEOUT;
                //}

                extraction.HistoricPricesExtractResult = webException.Status.ToString();
            }

            //was the page hit a success?
            if (extraction.HistoricPricesExtractResult == "SUCCESS")
            {
                string pageSource = null;

                using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream()))
                {
                    pageSource = streamReader.ReadToEnd();
                }

                /* check that prices exist for this symbol */

                if (pageSource.IndexOf(PAGE_NOT_EXIST) > -1)
                {
                    //doesnt exist so quit
                    extraction.HistoricPricesExtractResult = "PRICES_NOT_EXIST";
                }
                else
                {
                    //does so extract prices
                    extraction.DailyPrices = ExtractDailyPricesFromSource(pageSource);

                    //update the dailyprice
                    extraction.DailyPrices.ForEach(delegate(DailyPrice dailyPrice)
                    {
                        dailyPrice.SymbolId = symbol.SymbolId;
                    });
                }
            }

            return extraction;
        }

        private List<DailyPrice> ExtractDailyPricesFromSource(string pageSource)
        {
            if (string.IsNullOrEmpty(pageSource))
            {
                //empty page source
                throw new ArgumentNullException("pageSource can not be null or empty in this context");
            }

            List<DailyPrice> dailyPrices = new List<DailyPrice>();

            string[] dailyPriceLines = pageSource.Split(new char[] { '\n' });

            //check we have some prices
            if (dailyPriceLines.Length > 1)
            {
                //loop each price line
                for (int dailyPriceLineIndex = 1; dailyPriceLineIndex < dailyPriceLines.Length; dailyPriceLineIndex++)
                {
                    string dailyPriceLine = dailyPriceLines[dailyPriceLineIndex];

                    //split up line into price components e.g open, close etc
                    string[] dailyPriceComponents = dailyPriceLine.Split(new char[] { ',' });

                    //make sure we have all componets
                    if (dailyPriceComponents.Length == 7)
                    {
                        //create the daily price
                        DailyPrice dailyPrice = new DailyPrice()
                        {                            
                            PriceDate = Convert.ToDateTime(dailyPriceComponents[0]),
                            Open = Convert.ToDecimal(dailyPriceComponents[1]),
                            High = Convert.ToDecimal(dailyPriceComponents[2]),
                            Low = Convert.ToDecimal(dailyPriceComponents[3]),
                            Close = Convert.ToDecimal(dailyPriceComponents[4]),
                            Volume = Convert.ToInt32(dailyPriceComponents[5]),
                            AdjustedClose = Convert.ToDecimal(dailyPriceComponents[6])
                        };

                        //add to list
                        dailyPrices.Add(dailyPrice);
                    }
                }
            }

            return dailyPrices;
        }
    }
}
